﻿using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Windows.Forms;
using Kimgwajang.MidnightPeach.Generators;
using Kimgwajang.MidnightPeach.Schema;
using Kimgwajang.MidnightPeach.Properties;
using Kimgwajang.MidnightPeach.Utilities;
using System.Diagnostics;

namespace Kimgwajang.MidnightPeach.Forms
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        private Database _database;

        private PackageDataSet _packageDataSet;

        protected override void OnShown(EventArgs e)
        {
            base.OnShown(e);

            Text += string.Format(" v{0}.{1}", Utility.Version.Major, Utility.Version.Minor);

            btnGenerate.PerformClick();
        }

        private void LoadTreeViewNodes(Database database, PackageDataSet dataSet)
        {
            trvTree.Nodes.Clear();

            var query = from x in dataSet.Template
                        where x.Scope.ToLower() == "database"
                        orderby x.Name
                        select x;

            var databaseScopeNode = trvTree.Nodes.Add("Database Template");

            foreach (var row in query)
            {
                var templateNode = databaseScopeNode.Nodes.Add(row.Name);
                templateNode.Tag = row.Body;

                var databaseNode = templateNode.Nodes.Add(database.PascalName);
                databaseNode.Tag = dataSet.GeneratedCode.FindByTemplateNameDatabaseName(row.Name, database.PascalName).Code;
            }

            query = from x in dataSet.Template
                    where x.Scope.ToLower() == "table"
                    orderby x.Name
                    select x;

            var tableScopeNode = trvTree.Nodes.Add("Table Template");

            foreach (var row in query)
            {
                var templateNode = tableScopeNode.Nodes.Add(row.Name);
                templateNode.Tag = row.Body;

                foreach (var table in database.Tables)
                {
                    var tableNode = templateNode.Nodes.Add(table.PascalName);
                    tableNode.Tag = dataSet.GeneratedCode.FindByTemplateNameDatabaseName(row.Name, table.PascalName).Code;
                }
            }

            trvTree.ExpandAll();
        }

        #region helpers
        private void EnsurePath(string path)
        {
            var directory = Path.GetDirectoryName(path);
            Directory.CreateDirectory(directory);
        }
        #endregion

        #region PackageDataSet job
        private void ReadPackageData(PackageDataSet packageDataSet, Database database, string packagePath)
        {
            string packageDirectory = Path.GetDirectoryName(packagePath);

            #region variable
            var variables = new SortedDictionary<string, string>();

            foreach (var variableRow in packageDataSet.Variable)
                variables.Add(variableRow.Name, variableRow.Value);

            variables.Add("GeneratedTime", DateTime.Now.ToString());
            #endregion

            #region template
            foreach (var templateRow in packageDataSet.Template)
            {
                templateRow.Body = File.ReadAllText(string.Format(@"{0}\{1}.tpl", packageDirectory, templateRow.Name));

                if (templateRow.Scope.ToLower() == "database")
                {
                    string code = Generator.Build(variables, database, null, null, templateRow.Body);
                    packageDataSet.GeneratedCode.AddGeneratedCodeRow(templateRow, database.PascalName, code);
                }

                else if (templateRow.Scope.ToLower() == "table")
                {
                    foreach (var table in database.Tables)
                    {
                        string code = Generator.Build(variables, database, table, null, templateRow.Body);
                        packageDataSet.GeneratedCode.AddGeneratedCodeRow(templateRow, table.PascalName, code);
                    }
                }
            }
            #endregion
        }

        private void WritePackageData(string directoryToWrite, Database database, PackageDataSet dataSet)
        {
            foreach (var templateRow in dataSet.Template)
            {
                if (templateRow.Scope.ToLower() == "database")
                {
                    string code = dataSet.GeneratedCode.FindByTemplateNameDatabaseName(templateRow.Name, database.PascalName).Code;
                    string path = string.Format(@"{0}\{1}", directoryToWrite, string.Format(templateRow.TargetPath, database.PascalName));
                    EnsurePath(path);

                    File.WriteAllText(path, code);
                }

                else if (templateRow.Scope.ToLower() == "table")
                {
                    foreach (var table in database.Tables)
                    {
                        string code = dataSet.GeneratedCode.FindByTemplateNameDatabaseName(templateRow.Name, table.PascalName).Code;
                        string path = string.Format(@"{0}\{1}", directoryToWrite, string.Format(templateRow.TargetPath, table.PascalName));
                        EnsurePath(path);

                        File.WriteAllText(path, code);
                    }
                }
            }
        }
        #endregion

        #region TreeView event handlers
        private void trvTree_AfterSelect(object sender, TreeViewEventArgs e)
        {
            string generatedCode = e.Node.Tag as string;

            txtOutput.Text = generatedCode ?? string.Empty;
        }

        private void txtOutput_Click(object sender, EventArgs e)
        {
            if (chkCopy.Checked && txtOutput.Text.Length > 0)
                Clipboard.SetText(txtOutput.Text);
        }
        #endregion

        #region toolbar button event handlers
        private void btnGenerate_Click(object sender, EventArgs e)
        {
            btnWrite.Enabled = false;

            LoadForm loadForm = new LoadForm();
            if (loadForm.ShowDialog() != DialogResult.OK)
                return;

            _database = SchemaExtractor.Extract(loadForm.DbmlPath);
            _database.SortTables();

            TableForm tableForm = new TableForm(_database, loadForm.DbmlPath);
            if (tableForm.ShowDialog() != DialogResult.OK)
                return;

            _packageDataSet = new PackageDataSet();
            _packageDataSet.ReadXml(loadForm.PackagePath);

            PackageForm schemaForm = new PackageForm(_packageDataSet);
            if (schemaForm.ShowDialog() != DialogResult.OK)
                return;

            ReadPackageData(_packageDataSet, _database, loadForm.PackagePath);

            LoadTreeViewNodes(_database, _packageDataSet);

            btnWrite.Enabled = true;
        }

        private void btnWrite_Click(object sender, EventArgs e)
        {
#if DEBUG
            fbdFolder.SelectedPath = @"D:\Visual Studio 2008\Projects\MidnightPeachSolution\Memopad.EL4.Biz";
#else
            if (fbdFolder.ShowDialog() == DialogResult.OK)
#endif

            {
                WritePackageData(fbdFolder.SelectedPath, _database, _packageDataSet);
                MessageBox.Show(Resources.Saved);
            }
        }

        private void btnAbout_Click(object sender, EventArgs e)
        {
            var form = new AboutForm();
            form.ShowDialog();
        }

        private void btnHelp_Click(object sender, EventArgs e)
        {
            Process.Start(Resources.HomePage);
        }
        #endregion
    }
}